package com.example.java_gobang.api;

import com.example.java_gobang.model.MatchRequest;
import com.example.java_gobang.model.MatchResponse;
import com.example.java_gobang.game.Matcher;
import com.example.java_gobang.game.OnlineUserManager;
import com.example.java_gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

//通过这个类来处理匹配功能中的websocket请求
@Component
public class MatchAPI extends TextWebSocketHandler {
    //处理js对象
    private ObjectMapper objectMapper=new ObjectMapper();

    @Autowired
    private Matcher matcher;

    @Autowired
    private OnlineUserManager onlineUserManager;
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //玩家上线,就加入到onlineUserManger中

        //1.先获取用户当前的身份信息(谁在游戏大厅,建立连接)
        //这里session从websocket的,是从httpsession中拿到的,此处的键值对也是httpsession中的
        //此处的代码,之所以能够getAttributes(),全靠了注册websocket的时候
        //加上addInterceptors(new HttpSessionHandshakeInterceptor())这个逻辑
        //这个逻辑就HttpSession中的Attribute都给拿到WebSocketSession中了
        //在http登录逻辑中,往HttpSession中存了User数据:httpSession.setAttribute("user",user)
        //此时就可以在WebSocketSession中把之前HttpSession里面存的User对象给拿到了
        //注意: 此处拿到的user有可能为空,如果之前的用户没有通过http来进行登录的,
        //直接通过/game_hall这个url来 访问的游戏大厅页面,此时就会出现user为空的对象
        try {
            User user= (User)session.getAttributes().get("user");

            //2.先判定当前用户是否已经登录过(已经是在线状态),如果已经在线,就不该继续进行后续逻辑

            if(onlineUserManager.getFromGameHall(user.getUserId())!=null
             || onlineUserManager.getFromGameRoom(user.getUserId())!=null)
        {
                //当前用户已经登录!
                //针对这个 情况要告知客户端,你这里重复登录了
                MatchResponse response=new MatchResponse();
                //如果检测bug是意料值之内的用true,如果是意料之外的用false
                response.setOk(true);
                response.setReason("当前禁止多开");
                response.setMessage("repeatConnection");
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
                //此处直接关闭有点太激进了,还是返回一个特殊的message,供客户端判断,由客户端负责进行处理
                //session.close();//主动断开连接
                return;
            }

            //3.拿到了身份信息之后就可以把玩家设置成在线状态了
            onlineUserManager.enterGameHall(user.getUserId(),session);
            System.out.println("玩家 "+user.getUsername()+"进入游戏大厅");
        }catch (NullPointerException e){
            //e.printStackTrace();
            //出现空指针异常,说明当前的用户身份信息是空,用户未登录
            //把用户尚未登录这个信息返回回去
            System.out.println("[MatchAPI.afterConnectionEstablished]当前用户未登录! ");
            MatchResponse response=new MatchResponse();
            response.setOk(false);
            response.setReason("您尚未登录!不能进行后续匹配!");
            //通过ObjectMapper把MatchResponse对象转成json字符串
            //然后在包装上一层TextMessage(表示文本 格式的websocket是数据包)再进行传输
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //实现处理开始匹配请求和处理停止匹配请求
        User user=(User) session.getAttributes().get("user");
        //获取客户端给服务器发送的数据
        String payload=message.getPayload();
        //当前这个数据载荷是一个json格式的字符串,就需要把它转成java对象,类型为MathRequest
        //这个是从客户端读来的数据
       MatchRequest request= objectMapper.readValue(payload, MatchRequest.class);
       //这个是要返回给客户端的数据
       MatchResponse response=new MatchResponse();
       if(request.getMessage().equals("startMatch")){
           //进入匹配队列
           //先创建一个类表示匹配队列,把当前用户给加到匹配队列
           matcher.add(user);
           //把玩家信息放入匹配队列之后,就可以返回一个响应客户端
           response.setOk(true);
           response.setMessage("startMatch");
       }else if(request.getMessage().equals("stopMatch")){
           //退出匹配队列
           //先创建一个类表示匹配队列,把当前用户从队列中移除
           matcher.remove(user);
           //移除之后,就可以返回一个响应给客户端
           response.setOk(true);
           response.setMessage("stopMatch");
       }else{
           //非法情况
           response.setOk(false);
           response.setMessage("非法匹配");
       }
       String jsonString=objectMapper.writeValueAsString(response);
       session.sendMessage(new TextMessage(jsonString));

    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //玩家下线,从onlineUserManger中删除
        try {
            User user= (User)session.getAttributes().get("user");
            WebSocketSession temSession= onlineUserManager.getFromGameHall(user.getUserId());
            if(temSession==session) {
                //下线操作
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家正在匹配中,而websocket断开了,就应该移除到匹配队列中
            matcher.remove(user);
            }catch (NullPointerException e){
            System.out.println("[MatchAPI.handleTransportError]当前用户未登录! ");
           // e.printStackTrace();
            //出现空指针异常,说明当前的用户身份信息是空,用户未登录
            //不应该在连接关闭之后,还尝试发送消息给客户端(连接关闭就不能发送数据给客户端)

//            MatchResponse response=new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录!不能进行后续匹配!");
//            //通过ObjectMapper把MatchResponse对象转成json字符串
//            //然后在包装上一层TextMessage(表示文本 格式的websocket是数据包)再进行传输
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }

    }

    @Override
    //websocket连接关闭会触发这个方法
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //玩家下线,从onlineUserManger中删除
        try {
            User user= (User)session.getAttributes().get("user");
            WebSocketSession temSession= onlineUserManager.getFromGameHall(user.getUserId());
            //这里逻辑是登录的session和要下线的session是否相同,相同就下线
            if(temSession==session){
                //下线操作
                onlineUserManager.exitGameHall(user.getUserId());
            }
            //如果玩家正在匹配中,而websocket断开了,就应该移除到匹配队列中
            matcher.remove(user);
        }catch (NullPointerException e){
            System.out.println("[MatchAPI.afterConnectionClosed]当前用户未登录! ");
           // e.printStackTrace();
            //出现空指针异常,说明当前的用户身份信息是空,用户未登录
            //不应该在连接关闭之后,还尝试发送消息给客户端
//            MatchResponse response=new MatchResponse();
//            response.setOk(false);
//            response.setReason("您尚未登录!不能进行后续匹配!");
//            //通过ObjectMapper把MatchResponse对象转成json字符串
//            //然后在包装上一层TextMessage(表示文本 格式的websocket是数据包)再进行传输
//            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
}
